package org.zffc;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;

/**
 * @Description:
 * @Note: windows下启动emqx server
 * @Author: zhangfei
 * @Date: 2025/4/2 10:43
 **/
public class ZffcEMQXApplication {
    private static final Logger logger = LoggerFactory.getLogger(ZffcEMQXApplication.class);

    private static final Integer port = 18083;

    public static void main(String[] args) {
        try {
            // 加载配置
            Map<String, Object> config = loadYamlConfig("application.yml");
            List<Map<String, Object>> apps = getAppsList(config);

            // 启动EMQX
            for (Map<String, Object> appConfig : apps) {
                if ("emqx".equals(appConfig.get("name"))) {
                    Boolean flag = isPortAvailable(port);
                    if(flag) {
                        launchEmqxSilently(appConfig);
                    }else {
                        exit(appConfig);
                    }
                }
            }

        } catch (Exception e) {
            System.err.println("EMQX启动失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private static void launchEmqxSilently(Map<String, Object> appConfig) throws Exception {
        String cmd = (String) appConfig.get("cmd");
        String args = (String) appConfig.getOrDefault("args", "");
        String workingDir = (String) appConfig.getOrDefault("workingDir", "");
        String logFile = (String) appConfig.getOrDefault("logFile", "emqx.log");

        // 构建EMQX专用启动命令
        String fullCommand = buildEmqxCommand(cmd, args);

        ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", fullCommand);

        // 设置工作目录
        if (!workingDir.isEmpty()) {
            pb.directory(new File(workingDir));
        }

        // 重定向输出
        pb.redirectErrorStream(true);
        pb.redirectOutput(ProcessBuilder.Redirect.appendTo(new File(logFile)));

        // 启动
        Process process = pb.start();

        logger.info("EMQX已启动，日志输出到: " + new File(logFile).getAbsolutePath());
        logger.info("\n----------------------------------------------------------\n\t" +
                "Application Zffc-Boot is running! Access URLs:\n\t" +
                "Local: \t\thttp://localhost:18083" + "\n" +
                "----------------------------------------------------------");
    }

    private static void exit(Map<String, Object> appConfig) throws IOException {
        String cmd = (String) appConfig.get("cmd");
        String args = (String) appConfig.getOrDefault("exit", "");
        String workingDir = (String) appConfig.getOrDefault("workingDir", "");
        String logFile = (String) appConfig.getOrDefault("logFile", "emqx.log");

        // 构建EMQX专用启动命令
        String fullCommand = buildEmqxCommand(cmd, args);

        ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", fullCommand);

        // 设置工作目录
        if (!workingDir.isEmpty()) {
            pb.directory(new File(workingDir));
        }

        // 重定向输出
        pb.redirectErrorStream(true);
        pb.redirectOutput(ProcessBuilder.Redirect.appendTo(new File(logFile)));

        // 启动
        Process process = pb.start();

        logger.info("EMQX已停止，日志输出到: " + new File(logFile).getAbsolutePath());
    }

    /**
     * 检查本地端口是否可用
     * @param port 要检查的端口号
     * @return true表示端口可用，false表示已被占用
     */
    public static boolean isPortAvailable(int port) {
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            serverSocket.setReuseAddress(true);
            return true;
        } catch (IOException e) {
            // 端口已被占用或其他错误
            return false;
        }
    }

    private static String buildEmqxCommand(String cmd, String args) {
        // EMQX需要特殊处理，不使用start /B，而是依靠emqx.cmd自身的后台能力
        StringBuilder command = new StringBuilder();

        // 处理带空格的路径
        if (cmd.contains(" ")) {
            command.append("\"").append(cmd).append("\"");
        } else {
            command.append(cmd);
        }

        // 添加参数
        if (!args.isEmpty()) {
            command.append(" ").append(args);
        }

        return command.toString();
    }

    // 以下方法与之前示例相同
    private static Map<String, Object> loadYamlConfig(String filePath) throws Exception {
        Yaml yaml = new Yaml();
        try (InputStream in = Files.newInputStream(Paths.get(
                ZffcEMQXApplication.class.getClassLoader().getResource(filePath).toURI()))) {
            return yaml.load(in);
        }
    }

    @SuppressWarnings("unchecked")
    private static List<Map<String, Object>> getAppsList(Map<String, Object> config) {
        Object appsObj = config.get("apps");
        if (appsObj instanceof List) {
            return (List<Map<String, Object>>) appsObj;
        }
        throw new IllegalArgumentException("Invalid 'apps' configuration");
    }
}
